﻿using bat_sym.Helpers;
using bat_sym.Models;
using bat_sym.SimulationLogic;
using Microsoft.Practices.Prism.Commands;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;

namespace bat_sym.ViewModels
{
    public class MainWindowViewModel : ViewModelBase
    {
        private Simulation _simulation;

        public MainWindowViewModel(Simulation simulation)
        {
            if (_last == null)
            {
                _last = new DrawingImage(new DrawingGroup());
                var context = (_last.Drawing as DrawingGroup).Open();
                context.DrawRectangle(Brushes.White, null, new Rect(0, 0, 300,300));
                context.Close();
                //context = (_last.Drawing as DrawingGroup).Append();
            }

            _simulation = simulation;
            _simulation.SetCallback(new Action(() =>
                {
                    NotifyPropertyChanged("TotalBats");
                    NotifyPropertyChanged("CoopBats");
                    NotifyPropertyChanged("CompBats"); 
                    NotifyPropertyChanged("Days");
                    //NotifyPropertyChanged("Drawing");
                }), _last);

            SimulateCommand = new DelegateCommand(new Action(SimulateCommandExecute));
            StepCommand = new DelegateCommand(new Action(StepCommandExecute));
            GenerateCommand = new DelegateCommand(new Action(GenerateCommandExecute));

            SavePresetCommand = new DelegateCommand(new Action(SavePresetCommandExecute));
            LoadPresetCommand = new DelegateCommand(new Action(LoadPresetCommandExecute));
            DeletePresetCommand = new DelegateCommand(new Action(DeletePresetCommandExecute));

            NumberBar = new DrawingImage(new DrawingGroup());
            var context2 = (NumberBar.Drawing as DrawingGroup).Open();
            context2.DrawRectangle(Brushes.White, null, new Rect(0, 0, 10, 300));
            for (int i = 10; i < 300; i += 10)
            {
                context2.DrawText(new FormattedText(i.ToString(), CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("GenericSans"), 5, Brushes.Black), new Point(0, 290 - i));
            }
            context2.Close();
        }

        public DelegateCommand SimulateCommand { get; set; }
        public DelegateCommand StepCommand { get; set; }
        public DelegateCommand GenerateCommand { get; set; }

        public DelegateCommand SavePresetCommand { get; set; }
        public DelegateCommand LoadPresetCommand { get; set; }
        public DelegateCommand DeletePresetCommand { get; set; }

        public int MaxFoodLevel
        {
            get
            {
                return _simulation.MaxFoodLevel;
            }
        }

        private DrawingImage _last;

        public DrawingImage Drawing
        {
            get
            {
                return _last;
            }
        }

        private int _cfg_total;
        private int _cfg_percent;
        private int _cfg_comp;
        private int _cfg_coop;

        public int Coop 
        {
            get
            {
                return _cfg_coop;
            }

            set
            {
                _cfg_coop = value;
                _cfg_total = _cfg_coop + _cfg_comp;

                if (_cfg_total != 0)
                {
                    _cfg_percent = _cfg_comp * 100 / _cfg_total;
                }

                NotifyPropertyChanged("Total");
                NotifyPropertyChanged("Percent");
                NotifyPropertyChanged("Comp");
                NotifyPropertyChanged("Coop");
            }
        }

        public int Comp
        {
            get
            {
                return _cfg_comp;
            }

            set
            {
                _cfg_comp = value;
                _cfg_total = _cfg_coop + _cfg_comp;

                if (_cfg_total != 0)
                {
                    _cfg_percent = _cfg_comp * 100 / _cfg_total;
                }

                NotifyPropertyChanged("Total");
                NotifyPropertyChanged("Percent");
                NotifyPropertyChanged("Comp");
                NotifyPropertyChanged("Coop");
            }
        }

        public int Percent
        {
            get
            {
                return _cfg_percent;
            }

            set
            {
                _cfg_percent = value;
                if (_cfg_percent > 100)
                {
                    _cfg_percent = 100;
                }

                if (_cfg_percent < 0)
                {
                    _cfg_percent = 0;
                }

                var comp = (double)_cfg_total / 100 * _cfg_percent;
                _cfg_comp = (int)comp;
                _cfg_coop = _cfg_total - _cfg_comp;

                NotifyPropertyChanged("Total");
                NotifyPropertyChanged("Percent");
                NotifyPropertyChanged("Comp");
                NotifyPropertyChanged("Coop");
            }
        }

        public int Total
        {
            get
            {
                return _cfg_total;
            }

            set
            {
                _cfg_total = value;
                var comp = (double)_cfg_total / 100 * _cfg_percent;
                _cfg_comp = (int)comp;
                _cfg_coop = _cfg_total - _cfg_comp;

                NotifyPropertyChanged("Total");
                NotifyPropertyChanged("Percent");
                NotifyPropertyChanged("Comp");
                NotifyPropertyChanged("Coop");
            }
        }

        public DrawingImage NumberBar { get; set; }

        public int NormalFoodLevel
        {
            get
            {
                return _simulation.NormalFoodLevel;
            }
        }

        public ObservableCollection<string> Presets
        {
            get
            {
                return _simulation.Presets;
            }
        }

        public int CriticalFoodLevel
        {
            get
            {
                return _simulation.CriticalFoodLevel;
            }
        }

        public ObservableCollection<Bat> Bats
        {
            get
            {
                return _simulation.Bats;
            }
        }

        public ObservableCollection<ISimulationRule> Rules
        {
            get
            {
                return _simulation.Rules;
            }
        }

        public string PlayText
        {
            get
            {
                return _simulation.IsRunning ? "Stop" : "Play";
            }
        }

        public string SelectedPreset
        {
            get;
            set;
        }

        public bool IsStepEnabled
        {
            get
            {
                return !_simulation.IsRunning;
            }
        }

        public int CompBats
        {
            get
            {
                return _simulation.StatisticsManager._liveComp;
            }
        }

        public int CoopBats
        {
            get
            {
                return _simulation.StatisticsManager._liveCoop;
            }
        }

        public int TotalBats
        {
            get
            {
                return CompBats + CoopBats;
            }
        }

        public int Days
        {
            get
            {
                return _simulation.StatisticsManager.iteration;
            }
        }

        private void SimulateCommandExecute()
        {
            if (_simulation.IsRunning)
            {
                _simulation.StopSimulation();
            }
            else
            {
                _simulation.StartSimulation();
            }

            NotifyPropertyChanged("PlayText");
            NotifyPropertyChanged("IsStepEnabled");
        }

        private void StepCommandExecute()
        {
            _simulation.SimulateStep(null);
        }

        private void GenerateCommandExecute()
        {
            _simulation.Bats.Clear();
            var number = 0;
            for (int i = 0; i < _cfg_comp; i++)
            {
                _simulation.Bats.Add(new Bat { Behaviour = BatBehaviour.Cheating, FoodAmmount = _simulation.MaxFoodLevel, Label = "#" + number.ToString() });
                number++;
            }
            for (int i = 0; i < _cfg_coop; i++)
            {
                _simulation.Bats.Add(new Bat { Behaviour = BatBehaviour.Cooperative, FoodAmmount = _simulation.MaxFoodLevel, Label = "#" + number.ToString() });
                number++;
            }
            _simulation.StatisticsManager.Reset();

            _last = new DrawingImage(new DrawingGroup());
            var context = (_last.Drawing as DrawingGroup).Open();
            context.DrawRectangle(Brushes.White, null, new Rect(0, 0, 300, 300));
            context.Close();

            _simulation._drw = _last;

            NotifyPropertyChanged("Drawing");
        }

        private void SavePresetCommandExecute()
        {
            var window = new NameDialog();
            window.ShowDialog();
            if (window.OkClicked)
            {
                _simulation.SaveCurrentPreset(window.Filename, Coop, Comp);
            }
        }

        private void LoadPresetCommandExecute()
        {
            var res = _simulation.LoadPreset(SelectedPreset);
            Coop = res.Coops;
            Comp = res.Comps;
            GenerateCommandExecute();
        }

        private void DeletePresetCommandExecute()
        {
            _simulation.DeletePreset(SelectedPreset);
        }
    }
}
